package org.burningokr.service.dashboard.helper;

import org.burningokr.model.dashboard.LineChartLineKeyValues;
import org.burningokr.model.okr.KeyResult;
import org.burningokr.model.okr.Objective;
import org.burningokr.model.okr.histories.KeyResultHistory;
import org.burningokr.model.okrUnits.OkrChildUnit;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;

public class ProgressHelper {
  public static LineChartLineKeyValues getProgressForCompany(
          Collection<LineChartLineKeyValues> teamProgressLineChartValueList,
          long numberOfDays
  ) {
    LineChartLineKeyValues avgCompanyProgressLineChartKeyValues = new LineChartLineKeyValues();
    ArrayList<Double> companyProgress = new ArrayList<>();

    for (int i = 0; i < numberOfDays; i++) {
      double sumDay = 0;
      int numberOfTeamsThatDay = 0;
      for (LineChartLineKeyValues teamProgress : teamProgressLineChartValueList) {
        if (teamProgress.getData().size() > i && teamProgress.getData().get(i) != null) {
          sumDay += teamProgress.getData().get(i);
          numberOfTeamsThatDay++;
        }
      }
      if (numberOfTeamsThatDay > 0) {
        companyProgress.add(sumDay / numberOfTeamsThatDay);
      } else {
        companyProgress.add(null);
      }
    }

    avgCompanyProgressLineChartKeyValues.setName("Durchschnitt der Firma");
    avgCompanyProgressLineChartKeyValues.setData(companyProgress);

    return avgCompanyProgressLineChartKeyValues;
  }


  public static ArrayList<Double> getProgressForTeam(OkrChildUnit okrDepartment, LocalDate startDate, long numberOfDays) {
    ArrayList<Double> teamProgress = new ArrayList<>();
    ArrayList<ArrayList<Double>> objectiveProgressLists = new ArrayList<>();
    ArrayList<Objective> objectives = new ArrayList<>(okrDepartment.getObjectives());

    for (Objective objective : objectives) {
      objectiveProgressLists.add(getProgressForObjective(objective, startDate, numberOfDays));
    }

    return getDoubles(numberOfDays, teamProgress, objectiveProgressLists);
  }

  public static ArrayList<Double> getProgressForObjective(Objective objective, LocalDate startDate, long numberOfDays) {
    ArrayList<Double> objectiveProgress = new ArrayList<>();
    ArrayList<ArrayList<Double>> keyResultsProgressLists = new ArrayList<>();
    ArrayList<KeyResult> keyResults = new ArrayList<>(objective.getKeyResults());

    for (KeyResult keyResult : keyResults) {
      keyResultsProgressLists.add(getKeyResultProgressOfKeyResult(keyResult, startDate, numberOfDays));
    }

    return getDoubles(numberOfDays, objectiveProgress, keyResultsProgressLists);
  }

  /**
   * @param keyResult    KeyResult Objet of which zu get the progress-history
   * @param startDate    LocalDate from which it beginns
   * @param numberOfDays long Number of Days it's supposed to calculate the progress.
   * @return List of doubles(percentage) which contain the progress for every single day since startdate until numberOfDays after startDate is reached.
   * If first value of keyResultHistory is after startDate, all values until startDate will be null
   */
  public static ArrayList<Double> getKeyResultProgressOfKeyResult(
          KeyResult keyResult,
          LocalDate startDate,
          long numberOfDays
  ) {
    ArrayList<Double> keyResultProgress = new ArrayList<>();
    ArrayList<KeyResultHistory> keyResultHistories = new ArrayList<>(keyResult.getKeyResultHistory());
    keyResultHistories.sort(Comparator.comparing(KeyResultHistory::getDateChanged));
    LocalDate currentDate = startDate;

    for (long i = 0; i < numberOfDays; i++) {
      KeyResultHistory keyResultHistory = null;
      for (KeyResultHistory krh : keyResultHistories) {
        if (krh.getDateChanged().equals(currentDate)) {
          keyResultHistory = krh; // Can't use stream filter because java doesn't like it when variables used in lambdas aren't final
        }
      }
      if (keyResultHistory != null) {
        double target = keyResultHistory.getTargetValue() - keyResultHistory.getStartValue();
        double currentValue = keyResultHistory.getCurrentValue() - keyResultHistory.getStartValue();
        if (currentValue == 0) {
          keyResultProgress.add(0.0);
        } else {
          keyResultProgress.add(100 / target * currentValue);
        }
      } else {
        int size = keyResultProgress.size();
        if (size > 0) {
          keyResultProgress.add(keyResultProgress.get(size - 1));
        } else {
          keyResultProgress.add(null); // Adding null to filter out days without any key-result progress for keyResult in later calculations
        }
      }
      currentDate = currentDate.plusDays(1);
    }

    return keyResultProgress;
  }

  private static ArrayList<Double> getDoubles(long numberOfDays, ArrayList<Double> teamProgress, ArrayList<ArrayList<Double>> objectiveProgressLists) {
    for (int i = 0; i < numberOfDays; i++) {
      double currentDayValue = 0;
      int numberOfObjectives = 0;

      for (ArrayList<Double> objectiveProgressList : objectiveProgressLists) {
        if (objectiveProgressList.get(i) != null) {
          currentDayValue += objectiveProgressList.get(i);
          numberOfObjectives++;
        }
      }
      if (numberOfObjectives > 0) {
        currentDayValue = currentDayValue / numberOfObjectives;
        teamProgress.add(currentDayValue);
      } else {
        teamProgress.add(null); // Adding null to later filter out when objectives didn't have progress yet (Meaning no Key-Result) in later calculations
      }
    }
    return teamProgress;
  }
}
